package top.jacktgq.itheima.netty.byteBuf;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.CompositeByteBuf;
import org.junit.Test;
import top.jacktgq.utils.ByteBufUtil;

import java.nio.charset.StandardCharsets;

/**
 * @Author CandyWall
 * @Date 2021/3/23--12:32
 * @Description
 */
public class TestByteBuf {
    @Test
    /**
     * Netty提供的ByteBuf支持动态扩容
     */
    public void test1() {
        ByteBuf buf = ByteBufAllocator.DEFAULT.buffer();
        ByteBufUtil.log(buf);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 300; i++) {
            sb.append('a');
        }
        buf.writeBytes(sb.toString().getBytes(StandardCharsets.UTF_8));
        ByteBufUtil.log(buf);
    }

    @Test
    /**
     * 直接内存和堆内存
     */
    public void test2() {
        ByteBuf buf1 = ByteBufAllocator.DEFAULT.buffer();
        // 查看实现类：直接内存
        System.out.println(buf1.getClass());

        ByteBuf buf2 = ByteBufAllocator.DEFAULT.heapBuffer();
        // 查看实现类：堆内存
        System.out.println(buf2.getClass());
    }

    @Test
    /**
     * 池化和非池化：可以通过 JVM 启动参数进行设置，电脑上运行默认是池化，安卓上默认非池化
     * -Dio.netty.allocator.type={unpooled|pooled}
     */
    public void test3() {
        ByteBuf buf1 = ByteBufAllocator.DEFAULT.buffer();
        // 查看实现类：直接内存
        System.out.println(buf1.getClass());

        ByteBuf buf2 = ByteBufAllocator.DEFAULT.heapBuffer();
        // 查看实现类：堆内存
        System.out.println(buf2.getClass());
    }

    @Test
    /**
     * 测试 Netty 的零拷贝方法：slice，切片
     */
    public void testSlice() {
        ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(10);
        buf.writeBytes(new byte[]{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'});
        ByteBufUtil.log(buf);

        // 在切片的过程中没有发生数据复制
        ByteBuf buf1 = buf.slice(0, 5);
        ByteBuf buf2 = buf.slice(5, 5);

        ByteBufUtil.log(buf1);
        ByteBufUtil.log(buf2);

        // 修改后
        System.out.println("===============================================");
        buf1.setByte(0, 'z');
        ByteBufUtil.log(buf);
        ByteBufUtil.log(buf1);
        ByteBufUtil.log(buf2);

        System.out.println("释放原有ByteBuf内存");
        // 在释放内存之前，调用retain()方法，让refrenceCnt加1，抵消release减1的操作
        buf1.retain();
        buf2.retain();
        buf.release();
        // 切片后的子ByteBuf和父ByteBuf是共用一片内存空间的，
        // 因此释放回收父ByteBuf的内存空间，子ByteBuf也就无法被访问了
        ByteBufUtil.log(buf1);

        System.out.println("======================================================================");
        // 修改切片1中某个位置上的值，看看有没有改动原始buf上对应位置的值
        /*buf1.setByte(1, 'x');
        ByteBufUtil.log(buf1);
        ByteBufUtil.log(buf);*/

        // 切片后的某个子ByteBuf不能向其中添加元素了，否则会报错
        //buf1.writeByte('y');

        buf1.release();
        buf2.release();
    }

    @Test
    /**
     * 测试 Netty 的零拷贝方法：CompositeByteBuf，组合
     */
    public void testCompositeByteBuf() {
        ByteBuf buf1 = ByteBufAllocator.DEFAULT.buffer();
        buf1.writeBytes(new byte[]{'a', 'b', 'c', 'd', 'e'});
        ByteBuf buf2 = ByteBufAllocator.DEFAULT.buffer();
        buf2.writeBytes(new byte[]{'f', 'g', 'h', 'i', 'j'});

        // 组合两个ByteBuf
        // 1.传统方法，能实现，但是发生了数据的复制，如果数据量大，会影响性能
        /*ByteBuf buf = ByteBufAllocator.DEFAULT.buffer();
        buf.writeBytes(buf1).writeBytes(buf2);
        ByteBufUtil.log(buf);*/

        // 2.使用Netty提供的方法
        CompositeByteBuf compositeByteBuf = ByteBufAllocator.DEFAULT.compositeBuffer();
        // 组合的时候需要调用带有boolean变量的方法，这样ByteBuf的读写指针也会正常
        compositeByteBuf.addComponents(true, buf1, buf2);
        ByteBufUtil.log(compositeByteBuf);
        // 在释放内存之前，调用retain()方法，让refrenceCnt加1，抵消release减1的操作
        buf1.retain();
        buf2.retain();

        // 使用完之后释放
        buf1.release();
        buf2.release();
    }
}
